﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;

namespace ctem.gui.SignalChart
{
    public  partial class SignalChartBox : UserControl
    {
        #region События
        //public delegate void DrawPointHandler(Point point);
        //[Browsable(true)]
        //public event DrawPointHandler BeforeDrawPoint;
        //[Browsable(true)]
        //public event DrawPointHandler AfterDrawPoint;
        #endregion

        public bool IsLog = false;

        private Chart chart = new SignalChart.Chart();

        private double X1 = 0.0;
        private double X2 = 100.0;
        private double Y1 = -10.0;
        private double Y2 = 10.0;


        private int refreshInterval = 5;
        private double stepRestart = 0.0;
        private double limitForRestart = Double.PositiveInfinity;

        public void SetMagicNumberN(int N)
        {
            limitForRestart = N;
        }

        public void CollapsSignal(bool collapsed)
        {
            splitContainer1.Panel2Collapsed = collapsed;
        }

        public void SetAxisCaption(char axis, string caption, string metric)
        {
            if (axis == 'x')
            {
                label5.Text = caption;
                XMetric.Text = metric;
            }
            else
                if (axis == 'y')
                {
                    label6.Text = caption;
                    YMetric.Text = metric;
                }
        }


        public void Clear()
        {
            chart.Clear();
        }

        public RectangleF ViewRect
        {
            get { return chart.ViewRect; }
            set { chart.ViewRect = value; }
        }

        public int RefreshInterval
        {
            get { return refreshInterval; }
            set
            {
                refreshInterval = value > 0 ? value : refreshInterval;
                if (value <= 0)
                {
                    //TODO: заменить на запись в Лог
                    throw new Exception("RefreshInterval must't be less than zero");
                }
            }
        }

        public void RedrawPortNames()
        {
            listViewSeries.Items.Clear();
            for (int i = 0; i < chart.CountOfSeries; i++)
            {
                string[] str = new string[1];
                str[0] = chart.GetSeries(i).Name;
                listViewSeries.Items.Add(new ListViewItem(str, 0, chart.GetSeries(i).ColorOfPoints, listViewSeries.BackColor, new Font("Times New Roman", 10)));
            }
        }

        public Series GetSeries(string name)
        {
            return chart.GetSeries(name);
        }

        public void AddSeries(Series s)
        {
            chart.AddSeries(s);

            RedrawPortNames();
        }


        int step;
        public void AddItem(string SeriesName, PointF item)
        {
            
            step++;
            stepRestart++;

            if (stepRestart == (limitForRestart * chart.CountOfSeries+1))
            {
                stepRestart = 1;
                //step = 0;
                //Refresh();
                Clear();

            }

                chart.GetSeries(SeriesName).AddItem(new PointF(item.X, item.Y));

            if (step == refreshInterval*chart.CountOfSeries)
            {
                step = 0;
                pbSignalChart.Refresh();
            }

          
        }
        
        public SignalChartBox()
        {
            InitializeComponent();

            ViewRect = new RectangleF(new PointF((float)X1, (float)Y1), new SizeF((float)(X2 - X1), (float)(Y2 - Y1)));
            chart.CountOfPartsX =  10;
            chart.CountOfPartsY = 10;
        }

        private void pbSignalChart_Paint(object sender, PaintEventArgs e)
        {
            chart.RedrawChart(e.Graphics, this.pbSignalChart.Width, this.pbSignalChart.Height, IsLog);
            pbXAxis.Refresh();
            pbYAxis.Refresh();

        }


        private void pbSignalChart_Resize(object sender, EventArgs e)
        {
            Refresh();
        }

        private void pbXAxis_Paint(object sender, PaintEventArgs e)
        {
                if (IsLog)
                {
                    int count_of_parts = (int)Math.Truncate(Math.Log10(X2));

                    for (int i = 0; i < count_of_parts + 1; i++)
                    {
                        float delta_Re = (float)(pbSignalChart.Width) / (float)((Math.Log10(X2) - Math.Log10(X1)));

                        e.Graphics.DrawLine(new Pen(Brushes.Black, 1), new PointF(i * delta_Re, 0), new PointF(i * delta_Re, 15));
                        e.Graphics.DrawString((Math.Pow(10, i)).ToString(), new Font("Times New Roman", 10), Brushes.Black, new PointF(i * delta_Re, 10));

                        float k = (float)(delta_Re) / (float)Math.Log10(delta_Re);
                        float delta1 = delta_Re / 9F;
                            for (int j = 1; j < 10; j++)
                                e.Graphics.DrawLine(new Pen(Brushes.Black, 1), new PointF((float)(i * delta_Re + k * Math.Log10(j * delta1)), 0), new PointF((float)(i * delta_Re + k * Math.Log10(j * delta1)), 15));

                    }

                }
                else
                {
                    float delta_Im = (float)(X2 - X1) / (float)(chart.CountOfPartsX);
                    float delta_Re = (float)(pbSignalChart.Width) / (float)(chart.CountOfPartsX);

                    for (int i = 1; i < chart.CountOfPartsX; i++)
                    {
                        e.Graphics.DrawLine(new Pen(Brushes.Black, 1), new PointF(i * delta_Re, 0), new PointF(i * delta_Re, 15));

                        e.Graphics.DrawString((X1 + i * delta_Im).ToString("N2"), new Font("Times New Roman", 10), Brushes.Black, new PointF(i * delta_Re, 0));
                    }
                }
        }

        private void pbYAxis_Paint(object sender, PaintEventArgs e)
        {
            float delta_Im = (float)(Y2 - Y1) / (float)(chart.CountOfPartsX);
            float delta_Re = (float)(pbSignalChart.Height) / (float)(chart.CountOfPartsY);
            for (int i = 1; i < chart.CountOfPartsY; i++)
                {
                    e.Graphics.DrawLine(new Pen(Brushes.Black, 1), new PointF(pbYAxis.Width, pbYAxis.Height - i * delta_Re), new PointF(pbYAxis.Width - 15, pbYAxis.Height - i * delta_Re));
                    e.Graphics.DrawString(((float)(Y2 - (i * delta_Im))).ToString("N2"), new Font("Times New Roman", 10), Brushes.Black, new PointF(0, i * delta_Re+1));                    
                }
        }

        private void pbSignalChart_MouseMove(object sender, MouseEventArgs e)
        {
            if (IsLog)
            {
                float part = (float)((pbSignalChart.Width) / (Math.Log10(X2) - Math.Log10(X1)));
                //tbCurPos.Text = (Math.Pow(10,(ViewRect.Left + e.X)/part) / ZoomX).ToString("N2") + " ; " + (chart.ConvertY(e.Y - ViewRect.Top) / ZoomY).ToString("N2");
                tbCurPos.Text = (Math.Pow(10, (ViewRect.Left + e.X) / part)).ToString("N2") + " ; " + (Y2 - (e.Y * (Y2 - Y1) / pbSignalChart.Height)).ToString("N2");
            }
            else
                tbCurPos.Text = (e.X * (X2 - X1) / pbSignalChart.Width + X1).ToString("N2") + " ; " + (Y2 - (e.Y * (Y2 - Y1) / pbSignalChart.Height)).ToString("N2");
        }

        private void label2_Click(object sender, EventArgs e)
        {

        }

        private void button3_Click_1(object sender, EventArgs e)
        {
            splitContainer1.Panel2Collapsed = true; 
        }

        private void tbX1_TextChanged(object sender, EventArgs e)
        {
           // ViewRect.Left = Convert.ToInt32(tbX1.Text);
            double old_X1 = X1;
            try
            {
                X1 = Convert.ToDouble(tbX1.Text);
                if (X1 >= X2) 
                {
                    X1 = old_X1;
                    tbX1.Text = old_X1.ToString();

                    ToolTip tp = new ToolTip(); 
                    tp.Show("Значение должно быть меньше максимального по оси Х", tbX1,1000); 
                } 
                if (IsLog) 
                    if (X1 <= 0) 
                    { 
                        X1 = old_X1; 
                        tbX1.Text = old_X1.ToString();

                        ToolTip tp = new ToolTip();
                        tp.Show("Значение должно быть больше нуля", tbX1, 1000); 
                    }
            }
            catch
            {
                //X1 = old_X1;
                //tbX1.Text = old_X1.ToString();
                ToolTip tp = new ToolTip();
                tp.Show("Значение должно быть вещественным числом", tbX1, 1000); 
            }
            ViewRect = new RectangleF(new PointF((float)X1, (float)Y1), new SizeF((float)(X2 - X1), (float)(Y2 - Y1)));
            Refresh();
            
        }

        private void tbX2_TextChanged(object sender, EventArgs e)
        {
            try
            {
                double old_X2 = X2;
                X2 = Convert.ToDouble(tbX2.Text);
                if (X1 >= X2) 
                {
                    X2 = old_X2; tbX2.Text = old_X2.ToString();

                    ToolTip tp = new ToolTip();
                    tp.Show("Значение должно быть больше минимального по оси Х", tbX2, 1000); 
                }
                //if (IsLog) if (X1 <= 0) X1 = old_X1;

            }
            catch
            {
                ToolTip tp = new ToolTip();
                tp.Show("Значение должно быть вещественным числом", tbX2, 1000); 
            }
            ViewRect = new RectangleF(new PointF((float)X1, (float)Y1), new SizeF((float)(X2 - X1), (float)(Y2 - Y1)));
            Refresh();

        }

        private void tbY1_TextChanged(object sender, EventArgs e)
        {
            try
            {
                double old_Y1 = Y1;
                Y1 = Convert.ToDouble(tbY1.Text);
                if (Y1 >= Y2) 
                {
                    Y1 = old_Y1; tbY1.Text = old_Y1.ToString();
                    ToolTip tp = new ToolTip();
                    tp.Show("Значение должно быть меньше максимального по оси Y", tbY1, 1000); 
                }
            }
            catch
            {
                ToolTip tp = new ToolTip();
                tp.Show("Значение должно быть вещественным числом", tbY1, 1000); 

            }
            ViewRect = new RectangleF(new PointF((float)X1, (float)Y1), new SizeF((float)(X2 - X1), (float)(Y2 - Y1)));
            Refresh();

        }

        private void tbY2_TextChanged(object sender, EventArgs e)
        {
            try
            {
                double old_Y2 = Y2;
                Y2 = Convert.ToDouble(tbY2.Text);
                if (Y1 >= Y2) 
                {
                    Y2 = old_Y2; tbY2.Text = old_Y2.ToString();
                    ToolTip tp = new ToolTip();
                    tp.Show("Значение должно быть больше минимального по оси Y", tbY2, 1000); 
                }
            }
            catch
            {
                ToolTip tp = new ToolTip();
                tp.Show("Значение должно быть вещественным числом", tbY2, 1000); 
            }
            ViewRect = new RectangleF(new PointF((float)X1, (float)Y1), new SizeF((float)(X2 - X1), (float)(Y2 - Y1)));
            Refresh();

        }

        private void SignalChartBox_Load(object sender, EventArgs e)
        {
            if (IsLog)
            {
                X1 = 1.0;
                X2 = 1000.0;
                Y1 = -10.0;
                Y2 = 10.0;

                tbX1.Text = X1.ToString();
                tbX2.Text = X2.ToString();
                tbY1.Text = Y1.ToString();
                tbY2.Text = Y2.ToString();
            }
            else
            {
                X1 = 0.0;
                X2 = 100.0;
                Y1 = -10.0;
                Y2 = 10.0;

                tbX1.Text = X1.ToString();
                tbX2.Text = X2.ToString();
                tbY1.Text = Y1.ToString();
                tbY2.Text = Y2.ToString();
            }
        }

        private void SignalChartBox_Paint(object sender, PaintEventArgs e)
        {
            pbSignalChart.Refresh();
            pbXAxis.Refresh();
            pbYAxis.Refresh();
        }

    }
}